//////////////////////////////////////////////////////////////////////
// D3D10Engine.h
//
// SHEN Fangyang
// me@shenfy.com
//
// Copyright (C) SHEN Fangyang, 2011, All rights reserved.
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
//  Brief Description
//
//	Rendering Engine Interface
//
//////////////////////////////////////////////////////////////////////
#pragma once
#include <ManagerBase.h>
#include <BasisObj.h>
#include <IAStage.h>
#include <GUIEventDispatcher.h>
#include <GUIManager.h>
#include <CameraManager.h>
#include <PathArchive.h>
#include <boost/function.hpp>
#include <SceneManager.h>
#include <TextLabelManager.h>
#include <SceneObj.h>
#include <StatedObj.h>
#include <Effect.h>
#include <MultiTimer.h>

namespace grflib
{
	namespace engine
	{
        namespace aux
        {
			class CMousePicker;
        }

		namespace core
		{
			typedef _CManagerBase<IResource> CResourceManager;
			typedef _CManagerBase<IRenderable> CRenderableManager;
            typedef _CManagerBase<CStatedObj> CStatedObjectManager;
			typedef std::vector< std::pair<boost::shared_ptr<IRenderable>, D3DXMATRIX> > CRenderQueue;
			typedef std::pair<IRenderable *, D3DXMATRIX> render_queue_obj_type;
			class CTexture;

			//Singleton Rendering Engine
			class CEngine
			{
			public:
				~CEngine(void);
				static CEngine & Instance(void);

                enum ClearTargetFlag { CLEAR_NONE = 0, CLEAR_RGBA = 0x1, CLEAR_DEPTH = 0x2, CLEAR_STENCIL = 0x4, 
                    CLEAR_ALL = CLEAR_RGBA | CLEAR_DEPTH | CLEAR_STENCIL};

				//Life cycle
				int Run(TCHAR *wndName, UINT width, UINT height, bool bShowCursor = true);
				int Run(HWND hWnd, UINT width, UINT height, bool bShowCursor = true);

				//Default callbacks
				HRESULT DefaultOnCreate(ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext );
				HRESULT DefaultOnResize(ID3D10Device* pd3dDevice, IDXGISwapChain* pSwapChain, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext );
				void DefaultOnRelease(void *pUserContext);
				void DefaultOnDestroy(void *pUserContext);
				HRESULT DefaultRenderFrame(ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext);
				LRESULT DefaultMsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing, void* pUserContext);
				void DefaultOnFrameMove(double fTime, float fElapsedTime, void* pUserContext);

                //customized callbacks accessor
                inline boost::function<bool (void)> &InitSceneCallback() {return m_initSceneCallback;}
                inline boost::function<HRESULT (ID3D10Device *, const DXGI_SURFACE_DESC*, void*)> &PreCreateDeviceCallback() {return m_preCreateDeviceCallback;}
                inline boost::function<HRESULT (ID3D10Device *, const DXGI_SURFACE_DESC*, void*)> &PostCreateDeviceCallback() {return m_postCreateDeviceCallback;}
                inline boost::function<HRESULT (ID3D10Device*, IDXGISwapChain*, const DXGI_SURFACE_DESC *, void*)> &ResizeCallback() {return m_resizeCallback;}
                inline boost::function<void (void *)> &ReleaseCallback() {return m_releaseCallback;}
                inline boost::function<void (void *)> &DestroyCallback() {return m_destroyCallback;}
                inline boost::function<HRESULT (ID3D10Device*, double, float, void*)> &PreRenderCallback() {return m_renderCallback;}
                inline boost::function<HRESULT (ID3D10Device*, double, float, void*)> &PostRenderCallback() {return m_postRenderCallback;}
                inline boost::function<LRESULT (HWND, UINT, WPARAM, LPARAM, bool *, void *)> &MsgProcCallback() {return m_msgProc;}
                inline boost::function<void (double, float, void*)> &FrameMoveCallback() {return m_frameMoveCallback;}
                inline boost::function<ClearTargetFlag (UINT)> &PrePassCallback() {return m_prePassCallback; }

				//Manager accessor
				CSceneManager<CSceneObj, CRenderQueue> &GetSceneManager(void) {return m_sceneManager;}
				CResourceManager &GetResourceManager(void) {return m_resourceManager;}
				engine::aux::CGUIManager &GetGUIManager(void) {return m_guiManager;}
				CIAStage &GetIAStage(void) {return m_IAStage;}
				CCameraManager &GetCameraManager(void) {return m_cameraManager;}
				w32lib::CPathArchive &GetSearchPaths(void) {return m_searchPaths;}
				CRenderableManager &GetRenderableManager(void) {return m_renderableManager;}
                engine::aux::CTextLabelManager &GetTextLabelManager(void) {return m_txtLabelManager;}
                CStatedObjectManager &GetStatedObjectManager(void) {return m_statedObjectManager;}

				//Member accessor
				inline CRenderQueue &RenderQueue(void) {return m_renderQueue;}
				void SetClearColor(float *color)
				{ memcpy(m_clearColor, color, sizeof(float) * 4); }
				bool ChangeTechnique(ID3D10EffectTechnique *pTechnique); //true if changed
				inline ID3D10Device *GetD3DDevice(void) { return m_pd3dDevice; }
				boost::shared_ptr<grflib::engine::aux::CMousePicker> GetMousePicker(void);
                inline w32lib::CMultiTimer &Profiler(void) { return m_profiler; }
                inline UINT &PassNum(void) { return m_nPass; }

				//render function
				HRESULT SetRenderTarget(char *renderTargetName, char *depthStencilName);
                HRESULT SetRenderTarget(boost::shared_ptr<CTexture> &pRenderTargetTexture, 
                                        boost::shared_ptr<CTexture> &pDepthStencilTexture);
				void ResetRenderTarget(void);

			protected:
				CEngine(void); //prevent instantiation

            protected:
                //Additional customizable callbacks
				boost::function<bool (void)> m_initSceneCallback;
				boost::function<HRESULT (ID3D10Device *, const DXGI_SURFACE_DESC*, void*)> m_preCreateDeviceCallback;
				boost::function<HRESULT (ID3D10Device *, const DXGI_SURFACE_DESC*, void*)> m_postCreateDeviceCallback;
				boost::function<HRESULT (ID3D10Device*, IDXGISwapChain*, const DXGI_SURFACE_DESC *, void*)> m_resizeCallback;
				boost::function<void (void *)> m_releaseCallback;
				boost::function<void (void *)> m_destroyCallback;
				boost::function<HRESULT (ID3D10Device*, double, float, void*)> m_renderCallback;
				boost::function<HRESULT (ID3D10Device*, double, float, void*)> m_postRenderCallback;
				boost::function<LRESULT (HWND, UINT, WPARAM, LPARAM, bool *, void *)> m_msgProc;
				boost::function<void (double, float, void*)> m_frameMoveCallback;
                boost::function<ClearTargetFlag (UINT)> m_prePassCallback;

			protected:
				CIAStage m_IAStage;
				CResourceManager m_resourceManager; //stores textures, etc.
				engine::aux::CGUIManager m_guiManager; //stores GUI dialogs
                engine::aux::CTextLabelManager m_txtLabelManager; //stores text labels
				CCameraManager m_cameraManager; //stores cameras
				w32lib::CPathArchive m_searchPaths; //search path for loading mesh, texture, etc.
				CSceneManager<CSceneObj, CRenderQueue> m_sceneManager; //stores scene objects, in both hash table and scene graph
				CRenderableManager m_renderableManager; //stores IRenderable objects, ex. CStaticMesh
                CStatedObjectManager m_statedObjectManager; //stores statable objects capable of handling router messages

				CRenderQueue m_renderQueue; //IRenderable and associated world matrix

				ID3D10Device *m_pd3dDevice;
				float m_clearColor[4];
                UINT m_nPass;

				ID3D10RenderTargetView *m_pCurRenderTargetView;
				ID3D10DepthStencilView *m_pCurDepthStencilView;
				ID3D10RenderTargetView *m_pBackBufferRTV;
				ID3D10DepthStencilView *m_pBackBufferDSV;
				bool m_bRenderingToBackBuffer;

                //multi-timer for profiling
                w32lib::CMultiTimer m_profiler;
			};

		} //namespace core
	} //namespace engine
} //namespace grflib

#define _IAStage grflib::engine::core::CEngine::Instance().GetIAStage()
#define _ResrcMan grflib::engine::core::CEngine::Instance().GetResourceManager()
#define _CamMan grflib::engine::core::CEngine::Instance().GetCameraManager()
#define _GUIMan grflib::engine::core::CEngine::Instance().GetGUIManager()
#define _GUIDispatcher grflib::engine::core::CGUIEventManager<>::Instance()
#define _SearchPaths grflib::engine::core::CEngine::Instance().GetSearchPaths()
#define _SceneMan grflib::engine::core::CEngine::Instance().GetSceneManager()
#define _RenderableMan grflib::engine::core::CEngine::Instance().GetRenderableManager()
#define _RenderQueue grflib::engine::core::CEngine::Instance().RenderQueue()
#define _MsgRouter grflib::engine::AI::CMsgRouter::Instance()
#define _TxtMan grflib::engine::core::CEngine::Instance().GetTextLabelManager()
#define _AIMan grflib::engine::core::CEngine::Instance().GetStatedObjectManager()
#define _Profiler grflib::engine::core::CEngine::Instance().Profiler()